package de.dubiel.plung.client.play;

import java.util.ArrayList;
import java.util.List;

import com.google.gwt.dom.client.Touch;
import com.google.gwt.event.dom.client.GestureStartEvent;
import com.google.gwt.event.dom.client.GestureStartHandler;
import com.google.gwt.event.dom.client.MouseMoveEvent;
import com.google.gwt.event.dom.client.MouseMoveHandler;
import com.google.gwt.event.dom.client.TouchMoveEvent;
import com.google.gwt.event.dom.client.TouchMoveHandler;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.IsWidget;
import com.google.gwt.user.client.ui.Widget;
import com.google.inject.Inject;

import de.dubiel.plung.client.canvas.Circle;
import de.dubiel.plung.client.canvas.Drawable;
import de.dubiel.plung.client.canvas.Line;
import de.dubiel.plung.client.canvas.Vector;
import de.dubiel.plung.client.gin.ClientGinjector;
import de.dubiel.plung.shared.dao.User;

public class GameManager implements IsWidget {
    private static final int FIELD_WIDTH = 600;
    private static final int FIELD_HEIGHT = 400;
    private static final int LOCAL_PADDLE_X = 500;
    private static final int REMOTE_PADDLE_X = 100;
    private static final int PADDLE_WIDTH = 10;
    private static final int PADDLE_HEIGHT = 40;
    private static final int BALL_RADIUS = 4;

    private GamePanel panel = new GamePanel(FIELD_WIDTH, FIELD_HEIGHT);
    private Paddle localPaddle = new Paddle(PADDLE_WIDTH, PADDLE_HEIGHT);
    private Paddle remotePaddle = new Paddle(PADDLE_WIDTH, PADDLE_HEIGHT);
    private Circle ball = new Circle();
    private Line middleLine = new Line();
    private List<Drawable> gameObjects = new ArrayList<Drawable>();
    private ClientGinjector clientGinjector;

    private final Timer updateTimer = new Timer() {
        @Override
        public void run() {
            update();
        }
    };

    @Inject
    public GameManager(ClientGinjector clientGinjector) {
        this.clientGinjector = clientGinjector;
    }

    public void init() {
        gameObjects.add(middleLine);
        // Spielball
        gameObjects.add(ball);
        // Lokaler Schläger
        gameObjects.add(localPaddle);
        // Remote Schläger
        gameObjects.add(remotePaddle);
        initHandler();
        updateGameElementProperties();
        update();
    }

    public void startGame() {
        if (panel.isReadyToUse())
            updateTimer.scheduleRepeating(20);
    }

    public void stopGame() {
        updateTimer.cancel();
    }

    public void update() {
        panel.update(gameObjects);
    }

    private void initHandler() {
        panel.addMouseMoveHandler(new MouseMoveHandler() {
            public void onMouseMove(MouseMoveEvent event) {
                movePaddle(event.getRelativeX(panel.getElement()), event.getRelativeY(panel.getElement()));
            }
        });

        panel.addTouchMoveHandler(new TouchMoveHandler() {
            public void onTouchMove(TouchMoveEvent event) {
                event.preventDefault();
                if (event.getTouches().length() > 0) {
                    Touch touch = event.getTouches().get(0);
                    movePaddle(touch.getRelativeX(panel.getElement()), touch.getRelativeY(panel.getElement()));
                }
                event.preventDefault();
            }
        });

        panel.addGestureStartHandler(new GestureStartHandler() {
            public void onGestureStart(GestureStartEvent event) {
                event.preventDefault();
            }
        });        
    }

    private void movePaddle(int mouseX, int mouseY) {
        int newMouseY = Math.max(mouseY, 0 + PADDLE_HEIGHT / 2);
        newMouseY = Math.min(newMouseY, FIELD_HEIGHT - PADDLE_HEIGHT / 2);
        this.localPaddle.setPosition(new Vector(LOCAL_PADDLE_X, newMouseY));
    }

    /** Initialisert die Spielemenete, gibt ihnen Form, Größe, Farbe... */
    public void updateGameElementProperties() {
        User user = clientGinjector.getUserProvider().get();
        // Spielfeld
        panel.setBackgroundcolor(user.getFieldColor());
        // Mittelinie
        middleLine.setColor(user.getMiddleLineColor());
        middleLine.setWidth(1);
        middleLine.setStart(new Vector(FIELD_WIDTH / 2, 0));
        middleLine.setEnd(new Vector(FIELD_WIDTH / 2, FIELD_HEIGHT));
        // Spielball
        ball.setFillColor(user.getBallColor());
        ball.setWidth(1);
        ball.setCenterPoint(new Vector(FIELD_WIDTH / 2, FIELD_HEIGHT / 2));
        ball.setRadius(BALL_RADIUS);
        // Lokaler Schläger
        localPaddle.setFillColor(user.getLocalPaddleColor());
        localPaddle.setStrokeWidth(1);
        localPaddle.setPosition(new Vector(LOCAL_PADDLE_X, FIELD_HEIGHT / 2));
        // Remote Schläger
        remotePaddle.setFillColor(user.getRemotePaddleColor());
        remotePaddle.setStrokeWidth(1);
        remotePaddle.setPosition(new Vector(REMOTE_PADDLE_X, FIELD_HEIGHT / 2));
    }

    @Override
    public Widget asWidget() {
        return panel;
    }
}
